home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
001-025
/
disk_023
/
ver30
/
tty
/
intuition
/
ttyio.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-05-06
|
12KB
|
477 lines
/*
* Name: MicroEmacs
* Amiga terminal-dependent I/O (Intuition)
* Strategy and much code borrowed from the Lattice C
* example in the ROM Kernel manual.
* Version: 31
* Last edit: 21-Apr-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic
* Created: 21-Apr-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic
*/
/*
* Lots of includes.
*/
#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/tasks.h>
#include <exec/ports.h>
#include <exec/io.h>
#include <devices/console.h>
#include <libraries/dos.h>
#include <graphics/clip.h>
#include <graphics/view.h>
#include <graphics/rastport.h>
#include <graphics/layers.h>
#include <graphics/text.h>
#include <intuition/intuition.h>
#undef TRUE
#undef FALSE
#include "def.h" /* includes sysdef.h */
/*
* External functions. Declared explicitly
* to avoid problems with different compilers.
*/
extern char *OpenLibrary();
extern int OpenConsole();
extern struct Window *OpenWindow();
extern struct MsgPort *CreatePort();
extern struct IOStdReq *CreateStdIO();
extern struct Menu *InitEmacsMenu();
extern struct IntuiMessage *GetMsg();
extern LONG AbortIO();
extern LONG CloseDevice();
extern LONG ReplyMsg();
extern LONG SetMenuStrip();
extern LONG Wait();
/*
* Terminal I/O global variables
*/
#define NIBUF 128 /* Probably excessive. */
#define NOBUF 512 /* Not too big for 750/730. */
unsigned char obuf[NOBUF]; /* Output buffer */
int nobuf; /* # of bytes in above */
unsigned char ibuf[NIBUF]; /* Input buffer */
int ibufo, nibuf; /* head, # of bytes in ibuf */
int nrow; /* Terminal size, rows. */
int ncol; /* Terminal size, columns. */
extern char *version[]; /* Version information */
/* (I cheat and use it for */
/* the window title) */
/*
* Intuition global variables
*/
#define WINDOWGADGETS (WINDOWSIZING | WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE)
struct NewWindow MicroEMACS = {
0, 0, /* start position */
640, 200, /* width, height */
0, 1, /* detail pen, block pen */
MENUPICK | CLOSEWINDOW | /* IDCMP flags */
MOUSEBUTTONS | NEWSIZE,
WINDOWGADGETS | ACTIVATE, /* window flags */
NULL, /* pointer to first user gadget */
NULL, /* pointer to user checkmark */
NULL, /* title (filled in later) */
NULL, /* pointer to screen (none) */
NULL, /* pointer to superbitmap */
360,99,639,199, /* sizing limits min and max */
WBENCHSCREEN /* screen in which to open */
};
struct IntuitionBase *IntuitionBase; /* library bases */
struct GfxBase *GfxBase;
struct Window *EmacsWindow; /* Our window */
struct Menu *EmacsMenu; /* Our menu */
struct MsgPort *consoleWritePort; /* I/O ports */
struct MsgPort *consoleReadPort;
int intuitionMsgBit, /* Signal bits */
consoleMsgBit;
struct IOStdReq *consoleWriteMsg; /* I/O messages */
struct IOStdReq *consoleReadMsg;
unsigned char letter; /* Console input buffer */
USHORT class, /* Intuition event */
code, /* information */
qualifier;
APTR address;
SHORT x, y;
/*
* Some definitions
*/
#define INTUITION_MESSAGE ((LONG) 1 << intuitionMsgBit)
#define CONSOLE_MESSAGE ((LONG) 1 << consoleMsgBit)
/*
* Open up the virtual terminal MicroEMACS communicates with.
* Set up the window, console, and menu strip.
*/
extern int Enable_Abort; /* Do NOT allow abort! */
ttopen()
{
Enable_Abort = 0; /* Disable ^C */
GfxBase = (struct GfxBase *)
OpenLibrary("graphics.library", (LONG) 0);
if (GfxBase == NULL) /* Graphics lib */
cleanup(1);
IntuitionBase = (struct IntuitionBase *) /* Intuition */
OpenLibrary("intuition.library", (LONG) 0);
if (IntuitionBase == NULL)
cleanup(2);
/* Create our window */
MicroEMACS.Title = (UBYTE *) version[0];
EmacsWindow = OpenWindow(&MicroEMACS);
if (EmacsWindow == NULL)
cleanup(2);
/* Ports for reading and writing */
consoleWritePort = CreatePort("Emacs.con.write",(LONG) 0);
if (consoleWritePort == NULL)
cleanup(5);
consoleWriteMsg = CreateStdIO(consoleWritePort);
if (consoleWriteMsg == NULL)
cleanup(6);
consoleReadPort = CreatePort("Emacs.con.read",(LONG) 0);
if (consoleReadPort == NULL)
cleanup(7);
consoleReadMsg = CreateStdIO(consoleReadPort);
if (consoleReadMsg == NULL)
cleanup(8);
/* attach the console device to our window */
if (OpenConsole(consoleWriteMsg,consoleReadMsg,EmacsWindow) != 0)
cleanup(10);
/* attach a menu strip to the window */
EmacsMenu = InitEmacsMenu();
SetMenuStrip(EmacsWindow, EmacsMenu);
/* determine signal bit #'s */
intuitionMsgBit = EmacsWindow->UserPort->mp_SigBit;
consoleMsgBit = consoleReadPort->mp_SigBit;
/* initialize console read and input buffer */
QueueRead(consoleReadMsg,&letter);
nibuf = ibufo = 0;
/* Determine initial size of virtual terminal. */
ttsize(&nrow,&ncol);
return (0);
}
/*
* Close the virtual terminal, de-allocating
* everything we have allocated.
*/
ttclose()
{
ttflush();
AbortIO(consoleReadMsg);
CloseDevice(consoleWriteMsg);
cleanup(0);
Enable_Abort = 1;
}
/*
* Write a single character to the screen.
* Buffered for extra speed, so ttflush()
* does all the work.
*/
ttputc(c)
unsigned char c;
{
obuf[nobuf++] = c;
if (nobuf >= NOBUF)
ttflush();
}
/*
* Flush characters from the output buffer.
* Just blast it out with a console write call.
*/
ttflush()
{
if (nobuf > 0) {
ConWrite(consoleWriteMsg, obuf, nobuf);
nobuf = 0;
}
}
/*
* Input buffer management.
*
* The input buffer is a circular queue of characters
* that is updated and manipulated by the macros and
* functions below. This allows multiple Intuition
* events (menus, console input, etc.) to be buffered
* up until Emacs asks for them.
*/
#define CharsBuffered() (nibuf > 0 )
#define TypeInChar(c) if (nibuf < (NIBUF - 1))\
ibuf[(ibufo + nibuf++) % NIBUF] = c;
/*
* Return the next character in the input buffer.
*/
static GetInputChar()
{
unsigned char ch;
if (nibuf <= 0) /* this shouldn't happen. */
return 0;
ch = ibuf[ibufo++];
ibufo %= NIBUF;
nibuf--;
return (int) ch;
}
/*
* Get a character for Emacs, without echo or
* translation. Basically, handle Intuition
* events until we get one that signifies
* a character was typed in some way.
*/
ttgetc()
{
register struct IntuiMessage *message; /* IDCMP message */
register LONG wakeupmask;
register int charfound; /* have we got a character yet? */
if (CharsBuffered()) /* check input buffer */
return GetInputChar(); /* return immediately have one */
charfound = FALSE;
do {
wakeupmask = Wait(INTUITION_MESSAGE|CONSOLE_MESSAGE);
if (wakeupmask & CONSOLE_MESSAGE) { /* Keyboard */
GetMsg(consoleReadPort); /* free message */
TypeInChar(letter); /* do this FIRST */
QueueRead(consoleReadMsg, &letter);
charfound = TRUE;
}
if (wakeupmask & INTUITION_MESSAGE) { /* Intuition */
while(message = GetMsg(EmacsWindow->UserPort)) {
class = message->Class;
code = message->Code;
qualifier = message->Qualifier;
address = message->IAddress;
x = message->MouseX;
y = message->MouseY;
ReplyMsg(message);
/* Need ||= here because next event may */
/* not result in a character... */
charfound = charfound || HandleEvent();
} /* while (GetMsg()) */
} /* if Intuition event */
} while (charfound == FALSE);
return GetInputChar(); /* finally got a character. */
}
/*
* Handle the events we handle...
* The result indicates if we've
* put a character in the input buffer.
* All the event information is global,
* because there's a lot of it...
*/
extern int quit(); /* Defined by "main.c" */
static HandleEvent()
{
switch(class) {
case MENUPICK: /* fake the menu key */
if (code != MENUNULL)
return (DoMenu());
else
return (FALSE); /* No character found */
break;
case MOUSEBUTTONS: /* fake the mouse key */
return (DoMouse());
break;
case CLOSEWINDOW: /* Call quit() directly */
quit(FALSE, 1, KRANDOM); /* This loses if in a */
return (FALSE); /* dialogue... */
break;
}
return(FALSE); /* No char found */
}
/*
* Handle a menu selection by hand-crafting
* an escape sequence that looks like a function
* key to the terminal driver. Save the
* menu number and item number until the
* menu execution function can ask for it.
*/
int LastMenuNum; /* Menu number for KMENU `key' */
int LastItemNum; /* Menu item for KMENU `key' */
int LastSubItem; /* Subitem number (for completeness) */
#define CSI 0x9b /* Amiga command sequence introducer */
static DoMenu()
{
struct MenuItem *item, *ItemAddress();
while (code != MENUNULL) {
item = ItemAddress(EmacsMenu,(LONG) code);
LastMenuNum = MENUNUM(code); /* number of menu */
LastItemNum = ITEMNUM(code); /* item number */
LastSubItem = SUBNUM(code); /* subitem code */
code = item->NextSelect;
}
TypeInChar(CSI); /* fake the MENU key */
TypeInChar('M');
TypeInChar('~');
return (TRUE); /* found a character! */
}
/*
* Return the last menu selection numbers to
* the caller. Used by "ttymenu.c".
*/
ttmenu(menu,item,subitem)
int *menu, *item, *subitem;
{
*menu = LastMenuNum;
*item = LastItemNum;
*subitem = LastSubItem;
LastMenuNum = (USHORT)-1; /* Forget the values */
LastItemNum = (USHORT)-1; /* so they don't get re-used */
LastSubItem = (USHORT)-1;
}
/*
* Handle a mouse selection by inserting
* a "MOUSE key" (teer) sequence into the
* input buffer and saving the x, y and
* qualifier values for later.
*/
SHORT LastMouseX, LastMouseY; /* Position of mouse */
USHORT LastQualifier; /* Qualifier (shift key?) */
static DoMouse()
{
/* Save last mouse position */
if (code != SELECTDOWN)
return (FALSE);
LastMouseX = x - EmacsWindow->BorderLeft;
LastMouseY = y - EmacsWindow->BorderTop;
LastQualifier = qualifier;
TypeInChar(CSI); /* fake the MOUSE key */
TypeInChar('P'); /* P for Pointer */
TypeInChar('~');
return (TRUE); /* found a character! */
}
/*
* Return the last mouse click values to
* the caller. X and Y are translated
* so that (0,0) is at the edge of the
* top and left borders. Used by "ttymouse.c".
*/
ttmouse(x,y,qualifier)
SHORT *x, *y;
USHORT *qualifier;
{
*x = LastMouseX;
*y = LastMouseY;
*qualifier = LastQualifier;
LastMouseX = (SHORT)-1;
LastMouseY = (SHORT)-1;
LastQualifier = (USHORT)-1;
}
/*
* Return the current size of the virtual
* terminal to the caller. Placed in
* ttyio.c because it uses information
* that is only available to the virtual
* terminal handler.
*
* Assumes the WorkBench screen default
* font is TOPAZ_EIGHTY (8 wide by 8 high).
*/
ttsize(rows,cols)
int *rows, *cols;
{
*rows = (EmacsWindow->Height - /* have to take borders */
EmacsWindow->BorderTop - /* into account. */
EmacsWindow->BorderBottom) / 8;
*cols = (EmacsWindow->Width -
EmacsWindow->BorderLeft -
EmacsWindow->BorderRight) / 8;
}
/*
* Clean up.
* Fall through all the possible cases (0 means
* get rid of everything and start with the case
* that fits the error situation.
*/
extern LONG ClearMenuStrip();
extern LONG DeleteStdIO();
extern LONG DeletePort();
extern LONG CloseWindow();
extern LONG CloseLibrary();
static cleanup(prob)
{
switch (prob) {
case 0:
ClearMenuStrip(EmacsWindow);
DisposeMenus(EmacsMenu);
case 10:
case 8:
DeleteStdIO(consoleReadMsg);
case 7:
DeletePort(consoleReadPort);
case 6:
DeleteStdIO(consoleWriteMsg);
case 5:
DeletePort(consoleWritePort);
case 4:
CloseWindow(EmacsWindow);
case 2:
if (GfxBase != NULL) CloseLibrary(GfxBase);
case 1:
if (IntuitionBase != NULL) CloseLibrary(IntuitionBase);
break;
}
return(0);
}